---
title: Context Menu
description: Shows a menu activated by either a right-click or a long-press.
---

{/* prettier-ignore-start */}
{/* prettier-ignore-end */}

import Code from '@/components/Code.astro';
import { LinkButton } from '@/components/react/LinkButton';
import { Aside, Tabs, TabItem } from '@astrojs/starlight/components';
import importedCode from '@rnr/reusables/components/ui/context-menu?raw';

<LinkButton href='https://rn-primitives.vercel.app/context-menu'>Context Menu Primitive</LinkButton>
<LinkButton href='/components/text'>Text Component</LinkButton>
<LinkButton target='_blank' href='https://rnr-showcase.vercel.app/context-menu'>
  Demo
</LinkButton>

<br />

Shows a menu activated by either a right-click or a long-press.

### Installation

<Tabs>
  <TabItem label='CLI'> 
    ```bash
    npx @react-native-reusables/cli@latest add context-menu
    ```
  </TabItem>
  <TabItem label='Manual'>
    <Aside type='tip' title='Dependencies'>
      Before copy/pasting, add the <a href='https://rn-primitives.vercel.app/context-menu' className='text-white font-bold'> context-menu primitive</a> and the <a href='/components/text' className='text-white font-bold'>text component</a> to your project.
    </Aside>

    <br />

    **Copy/paste the following code to `~/components/ui/context-menu.tsx`:**

    <Code code={importedCode} lang='tsx' title='~/components/ui/context-menu.tsx' />
  </TabItem>
</Tabs>

### Usage

<Aside type="caution">

  Requires a `<PortalHost />` as the last child of your `<Root/>` (`app/_layout.tsx`) component

  ```tsx
  import { PortalHost } from '@rn-primitives/portal';

  function Root() {
    return (
      <>
        <Stack />
        {/* Default Portal Host (one per app) */}
        <PortalHost />
      </>
    );
  }
  ```

</Aside>

```tsx
import * as React from 'react';
import { Platform, View } from 'react-native';
import Animated, { FadeIn } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
  ContextMenu,
  ContextMenuCheckboxItem,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuLabel,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from '~/components/ui/context-menu';
import { Text } from '~/components/ui/text';

function Example() {
  const insets = useSafeAreaInsets();
  const contentInsets = {
    top: insets.top,
    bottom: insets.bottom,
    left: 12,
    right: 12,
  };
  const [checkboxValue, setCheckboxValue] = React.useState(false);
  const [subCheckboxValue, setSubCheckboxValue] = React.useState(false);
  const [radioValue, setRadioValue] = React.useState('pedro');

  return (
        <ContextMenu>
          <ContextMenuTrigger className='flex h-[150px] w-full max-w-[300px] mx-auto web:cursor-default items-center justify-center rounded-md border border-foreground border-dashed'>
            <Text className='text-foreground text-sm native:text-lg'>
              {Platform.OS === 'web' ? 'Right click here' : 'Long press here'}
            </Text>
          </ContextMenuTrigger>

          <ContextMenuContent align='start' insets={contentInsets} className='w-64 native:w-72'>
            <ContextMenuItem inset>
              <Text>Back</Text>
              <ContextMenuShortcut>⌘[</ContextMenuShortcut>
            </ContextMenuItem>
            <ContextMenuItem inset disabled>
              <Text>Forward</Text>
              <ContextMenuShortcut>⌘]</ContextMenuShortcut>
            </ContextMenuItem>
            <ContextMenuItem inset>
              <Text>Reload</Text>
              <ContextMenuShortcut>⌘R</ContextMenuShortcut>
            </ContextMenuItem>

            <ContextMenuSub>
              <ContextMenuSubTrigger inset>
                <Text>More Tools</Text>
              </ContextMenuSubTrigger>
              <ContextMenuSubContent className='web:w-48 native:mt-1'>
                <Animated.View entering={FadeIn.duration(200)}>
                  <ContextMenuItem>
                    <Text>Save Page As...</Text>
                    <ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <Text>Create Shortcut...</Text>
                  </ContextMenuItem>

                  <ContextMenuSeparator />
                  <ContextMenuItem>
                    <Text>Developer Tools</Text>
                  </ContextMenuItem>
                </Animated.View>
              </ContextMenuSubContent>
            </ContextMenuSub>

            <ContextMenuSeparator />
            <ContextMenuCheckboxItem
              checked={checkboxValue}
              onCheckedChange={setCheckboxValue}
              closeOnPress={false}
            >
              <Text>Show Bookmarks Bar</Text>
              <ContextMenuShortcut>⌘⇧B</ContextMenuShortcut>
            </ContextMenuCheckboxItem>
            <ContextMenuCheckboxItem
              checked={subCheckboxValue}
              onCheckedChange={setSubCheckboxValue}
              closeOnPress={false}
            >
              <Text>Show Full URLs</Text>
            </ContextMenuCheckboxItem>
            <ContextMenuSeparator />
            <ContextMenuRadioGroup value={radioValue} onValueChange={setRadioValue}>
              <ContextMenuLabel inset>People</ContextMenuLabel>
              <ContextMenuSeparator />
              <ContextMenuRadioItem value='pedro' closeOnPress={false}>
                <Text>Elmer Fudd</Text>
              </ContextMenuRadioItem>
              <ContextMenuRadioItem value='colm' closeOnPress={false}>
                <Text>Foghorn Leghorn</Text>
              </ContextMenuRadioItem>
            </ContextMenuRadioGroup>
          </ContextMenuContent>
        </ContextMenu>
  );
}
```

## Props

### ContextMenu

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |     Note     |
| :----------: | :----------------------: | :----------: |
| onOpenChange| (value: boolean) => void |                         |
|   asChild    |         boolean          |       _(optional)_      |
|  relativeTo  | 'longPress' \| 'trigger' | Native Only_(optional)_ |

### ContextMenuTrigger

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
|  inset  | boolean | _(optional)_ |

### ContextMenuPortal

|    Prop    |               Type               |         Note          |
| :--------: | :------------------------------: | :-------------------: |
| children\* |         React.ReactNode          |                       |
| forceMount |        true \| undefined         |     _(optional)_      |
|  hostName  |              string              | Web Only _(optional)_ |
| container  | HTMLElement \| null \| undefined | Web Only _(optional)_ |

### ContextMenuContent

Extends [`View`](https://reactnative.dev/docs/view#props) props

|          Prop           |                     Type                     |           Note           |
| :---------------------: | :------------------------------------------: | :----------------------: |
|         asChild         |                   boolean                    |       _(optional)_       |
|      overlayStyle       |            StyleProp\<ViewStyle>             |       _(optional)_       |
|    overlayClassName     |                    string                    |       _(optional)_       |
|       forceMount        |              true \| undefined               |       _(optional)_       |
|       alignOffset       |                    number                    |       _(optional)_       |
|         insets          |                    Insets                    |       _(optional)_       |
|     avoidCollisions     |                   boolean                    |       _(optional)_       |
|          align          |         'start' \| 'center' \| 'end'         |       _(optional)_       |
|          side           |              'top' \| 'bottom'               |       _(optional)_       |
|       sideOffset        |                    number                    |       _(optional)_       |
| disablePositioningStyle |                   boolean                    | Native Only _(optional)_ |
|          loop           |                   boolean                    |  Web Only _(optional)_   |
|    onCloseAutoFocus     |            (event: Event) => void            |  Web Only _(optional)_   |
|     onEscapeKeyDown     |        (event: KeyboardEvent) => void        |  Web Only _(optional)_   |
|  onPointerDownOutside   |  (event\: PointerDownOutsideEvent) => void   |  Web Only _(optional)_   |
|     onFocusOutside      |      (event: FocusOutsideEvent) => void      |  Web Only _(optional)_   |
|    onInteractOutside    | PointerDownOutsideEvent \| FocusOutsideEvent |  Web Only _(optional)_   |
|    collisionBoundary    |  Element \| null \| Array\<Element \| null>  |  Web Only _(optional)_   |
|         sticky          |            'partial' \| 'always'             |  Web Only _(optional)_   |
|    hideWhenDetached     |                   boolean                    |  Web Only _(optional)_   |

### ContextMenuGroup

Extends [`Text`](https://reactnative.dev/docs/text#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |

### ContextMenuLabel

Extends [`Text`](https://reactnative.dev/docs/text#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |

### ContextMenuItem

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
| textValue | boolean | _(optional)_ |
| closeOnPress | boolean | _(optional)_ |

### ContextMenuCheckboxItem

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|     Prop     |           Type           |           Note          |
| :----------: | :----------------------: | :---------------------: |
|   checked*   |         boolean          |                         |
|onCheckedChange*| (value: boolean) => void |                       |
|   textValue* |         string           |                         |
|  asChild     |         boolean          |       _(optional)_      |
| closeOnPress |         boolean          | Native Only_(optional)_ |

### ContextMenuRadioGroup

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |           Note          |
| :----------: | :----------------------: | :---------------------: |
|   value*   |         boolean          |                         |
|onValueChange*| (value: boolean) => void |                         |
|  asChild     |         boolean          |       _(optional)_      |

### ContextMenuRadioItem

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|     Prop     |           Type           |           Note          |
| :----------: | :----------------------: | :---------------------: |
|   value*     |         boolean          |                         |
|onCheckedChange*| (value: boolean) => void |                       |
|  asChild     |         boolean          |       _(optional)_      |
| closeOnPress |         boolean          | Native Only_(optional)_ |

### ContextMenuSeparator

Extends [`View`](https://reactnative.dev/docs/view#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
| decorative | boolean | _(optional)_ |

### ContextMenuSub

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |     Note     |
| :----------: | :----------------------: | :----------: |
|   asChild    |         boolean          | _(optional)_ |
| defaultOpen  |         boolean          | _(optional)_ |
|     open     |         boolean          | _(optional)_ |
| onOpenChange | (value: boolean) => void | _(optional)_ |

### ContextMenuSubTrigger

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| textValue | string | _(optional)_ |
| asChild | boolean | _(optional)_ |

### ContextMenuSubContent

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
| forceMount | true /| undefined | _(optional)_ |

### ContextMenuShortcut

Extends [`Text`](https://reactnative.dev/docs/text#props) props